#本文档定义client的窗口类
from PyQt5.QtWidgets import QWidget,QListWidgetItem
from ui.online import Ui_online
from PyQt5.QtGui import QTextCursor,QCloseEvent
from ui.privatesays import Ui_fm_PrivateSays
import  time


#定义用户在线窗口，这是client的第一个窗口，供用户上线并使用
#该类继承自PyQt小部件类Qwidget
class Qprivatesays(QWidget):
    def __init__(self,saysme,saysto,saystoname,closef,saysf,isfamily = False,parent = None):
        super(Qprivatesays,self).__init__(parent)
        self.ui = Ui_fm_PrivateSays()
        self.ui.setupUi(self)
        self.__saysto = saysto
        self.__saystoname = saystoname
        self.__saysme = saysme
        self.__isfamily = isfamily
        if isfamily:
            self.setWindowTitle('talk in: '+ '%s %s'%(str(self.__saysto),self.__saystoname))
        else:
            self.setWindowTitle('talk to: ' + '%s %s' % (str(self.__saysto), self.__saystoname))
        self.__closef = closef #窗口关闭时的事件回调，提供给使用者注册，执行清理操作
        self.__saysf = saysf  #提供给本窗口执行says操作，使用者注册
        self.ui.lineEdit.returnPressed.connect(self.__says)

    def closeEvent(self, QCloseEvent):#closeEvent方法重写
        #这里需要通知父窗口Qonline，删除其中保存的自己的引用
        self.__closef(self.__saysto,self.__isfamily)

    def __says(self):
        says = self.ui.lineEdit.text()
        self.ui.lineEdit.clear()
        self.__saysf(self.__isfamily,self.__saysto,says)
        #给自己显示一份
        # timestr = time.strftime('%H:%M:%S', time.localtime(time.time()))
        timestr = ''
        self.ui.textBrowser.append('【' + 'me' + timestr + ' says】:' + says)
        self.ui.textBrowser.moveCursor(QTextCursor.End)

    #接口给使用者或上级使用
    def appendsays(self,says):
        # timestr = time.strftime('%H:%M:%S', time.localtime(time.time()))
        timestr = ''
        #self.ui.textBrowser.append('【' + str(self.__saysto) + timestr + ' says】:' + says)
        if self.__isfamily :
            self.ui.textBrowser.append(says)
        else:
            self.ui.textBrowser.append('【%s %s'%(str(self.__saysto),self.__saystoname) +  timestr + ' says】:' + says)
        self.ui.textBrowser.moveCursor(QTextCursor.End)

class Qonline(QWidget):
    #此处定义SAYS类型常量，供自己和下层模块使用
    SAYS_TYPE_PRIVATE = 1 #私有SAYS类型
    SAYS_TYPE_PUB     =2  #公开SAYS类型
    SAYS_TYPE_GROUP    =3  #组SAYS类型，此处其实2可以与之合并，比如将GROUPID设置为0表示广播
    def __init__(self):
        super(Qonline,self).__init__()
        self.ui = Ui_online()
        self.ui.setupUi(self)
        self.__saysprocf = None #定义says处理接口，使用者注册（says_type,says,saysto）
        self.setWindowTitle('family talks')
        self.__frienddict = {}#c存储friend相关{ikey:{'Q':Qprivatesays,';li':widgetlistitem,'leavemsgs':leavemsgs}
        self.__familydict = {}#存储family相关{familyid:{'Q':Qprivatesays,';li':widgetlistitem,'leavemsgs':leavemsgs}
        self.__persondict = {}#存储person相关{personid:{'Q':Qprivatesays,';li':widgetlistitem,'leavemsgs':leavemsgs}
        self.__saysme = 0 #自己的ikey
        self.__saysmename = ''
        #设置槽方法
        #self.ui.lineEdit.returnPressed.connect(self.__sayspublic)
        #self.ui.listWidget.itemDoubleClicked.connect(self.__friendlistItemDoubleClick)
        self.ui.listWidget.itemDoubleClicked.connect(self.__rflistItemDoubleClicked)

    #定义privatesays 接口，该接口提供给clientdo调用，当收到并解析为私有消息时，调用

    #定义privatesays方法，注册给privateQ使用
    def __saysprivate(self,isfamily,saysto,says):

        if self.__saysprocf is not None:
            self.__saysprocf(isfamily,says,saysto)

    def __privateQclose(self,saysto,isfamily):#提供给privateQ的关闭处理接口
        #此处可加锁保护
        if isfamily:
            self.__familydict.get(saysto).pop('Q')
        else:
            self.__persondict.get(saysto).pop('Q')

    def __rflistItemDoubleClicked(self,listitem):
        saysto = listitem.data(5)
        saystoname = listitem.data(6)
        if listitem.data(7) == 'family':
            isfamily = True
            dodict = self.__familydict
        else:
            dodict = self.__persondict
            isfamily = False

        # 重复点击判断
        if dodict.get(saysto).get('Q') is not None:
            return

        # 特别注意，此处qprivate为局部变量，函数结束后为空，故部件最终不能恒久显示，需要保存到self的全局，
        # 由于可能打开多个所以要加入到一个链表self.__privateQlist
        qprivate = Qprivatesays(self.__saysme, saysto, saystoname, self.__privateQclose, self.__saysprivate,isfamily)
        # 此处可能要加锁，避免在增加的瞬间，线程抢占，又remove了
        dodict.get(saysto).update({'Q': qprivate})

        # 将leave内容 append出来
        leave_msgs = dodict.get(saysto).get('leavemsgs')
        if leave_msgs is not None:
            for says in leave_msgs:
                qprivate.appendsays(says)
            dodict.get(saysto).pop('leavemsgs')
            # 恢复listitem显示
            listitem = dodict.get(saysto).get('li')
            listitem.setText('%s %s %s' % (listitem.data(7),str(saysto), saystoname))
        qprivate.show()

    def __friendlistItemDoubleClick(self,listitem):
        saysto = listitem.data(5)
        saystoname = listitem.data(6)

        #重复点击判断
        if self.__frienddict.get(saysto).get('Q') is not None:
            return

        # 特别注意，此处qprivate为局部变量，函数结束后为空，故部件最终不能恒久显示，需要保存到self的全局，
        # 由于可能打开多个所以要加入到一个链表self.__privateQlist
        qprivate = Qprivatesays(self.__saysme,saysto,saystoname,self.__privateQclose,self.__saysprivate)
        # 此处可能要加锁，避免在增加的瞬间，线程抢占，又remove了
        self.__frienddict.get(saysto).update({'Q': qprivate})

        # 将leave内容 append出来
        leave_msgs = self.__frienddict.get(saysto).get('leavemsgs')
        if leave_msgs is not None:
            for says in leave_msgs:
                qprivate.appendsays(says)
            self.__frienddict.get(saysto).pop('leavemsgs')
            #恢复listitem显示
            listitem = self.__frienddict.get(saysto).get('li')
            listitem.setText('%s %s'%(str(saysto),saystoname))

    def __sayspublic(self):
        says = self.ui.lineEdit.text()
        self.ui.lineEdit.clear()
        # 给自己显示一份
        # timestr = time.strftime('%H:%M:%S', time.localtime(time.time()))
        timestr = ''
        self.ui.textBrowser.append('【' + 'me' + timestr + ' says】:' + says)
        self.ui.textBrowser.moveCursor(QTextCursor.End)
        if self.__saysprocf is not None:
            self.__saysprocf(self.SAYS_TYPE_PUB,says)

    # 外部接口，供clientdo调用
    #定义部件接口
    def setSaysf(self,func):#设置部件的says发送的处理接口
        self.__saysprocf = func

    def setsaysme(self,id,name):
        self.__saysme = id
        self.__saysmename = name
        #设置id lbl
        self.ui.lbl_talkid.setText('welcome,%d %s'%(id,name))

    def setrf(self,rfdict):
        self.ui.listWidget.clear()
        familylist = rfdict['familys']
        for family in familylist:#先加family
            familyid = family['id']
            familyname = family['name']
            listitem = QListWidgetItem('family %s %s' % (str(familyid), familyname), self.ui.listWidget)
            listitem.setData(5, familyid)  # 5存储id
            listitem.setData(6, familyname)  # 6存储name
            listitem.setData(7,"family")    #存储属性标记
            self.ui.listWidget.addItem(listitem)
            self.__familydict.update({familyid: {'li': listitem}})
        for family in familylist:  # 再加person
            familypersons = family['persons']
            for familyperson in familypersons:
                personid = familyperson['id']
                personname = familyperson['name']
                listitem = QListWidgetItem('person %s %s' % (str(personid), personname), self.ui.listWidget)
                listitem.setData(5, personid)  # 5存储id
                listitem.setData(6, personname)  # 6存储name
                listitem.setData(7, "person")  # 存储属性标记
                self.ui.listWidget.addItem(listitem)
                self.__persondict.update({personid: {'li': listitem}})

    def setfriends(self,friendlist):
        self.ui.listWidget.clear()
        for i in friendlist:#这里每个i也是一个list[id,name]
            id = i[0]
            name = i[1]
            if id is not self.__saysme: #不加自己
                listitem = QListWidgetItem('%s %s'%(str(id),name), self.ui.listWidget)
                listitem.setData(5, int(id))  # 5存储id
                listitem.setData(6,name)   #6存储name
                self.ui.listWidget.addItem(listitem)
                self.__frienddict.update({id: {'li': listitem}})

    def appendfriend(self,listfriend):
        id = listfriend[0]
        name = listfriend[1]
        listitem = QListWidgetItem('%s %s'%(str(id),name), self.ui.listWidget)
        listitem.setData(5, int(id))  # 1存储id
        listitem.setData(6,name) #6存储name
        self.ui.listWidget.addItem(listitem)
        self.__frienddict.update({id: {'li': listitem}})

    def recvsays(self,sayswho,saysto,isfamily,familyid,saystiem,says):

        if isfamily:
            #获得sayswho名
            listitem = self.__persondict.get(sayswho).get('li')
            if listitem is None:
                self._log("exception, friend %d,who's listitem is None" % sayswho)
                return
            sayswhoname = listitem.data(6)
            Qprivate = self.__familydict.get(familyid).get('Q')
            if Qprivate is not None:  # 窗口是否已打开
                Qprivate.appendsays(str(sayswho)+' '+ sayswhoname+' says :'+says)
            else:  # 以下为留言功能
                leave_msgs = self.__familydict.get(familyid).get('leavemsgs')
                if leave_msgs is None:
                    self.__familydict.get(familyid).update({'leavemsgs': [says]})
                    leave_msgs_num = 1
                else:
                    leave_msgs.append(says)
                    self.__familydict.get(familyid).update({'leavemsgs': leave_msgs})
                    leave_msgs_num = len(leave_msgs)
                listitem = self.__familydict.get(familyid).get('li')
                listitem.setText("%s %s %s" % (listitem.data(7),str(sayswho), listitem.data(6)) + ' got new messages(%d)' % leave_msgs_num)
        else:
            listitem = self.__persondict.get(sayswho).get('li')
            if listitem is None:  # 异常，忽略
                return
            Qprivate = self.__persondict.get(sayswho).get('Q')
            if Qprivate is not None:  # 窗口是否已打开
                Qprivate.appendsays(says)
            else:  # 以下为留言功能
                leave_msgs = self.__persondict.get(sayswho).get('leavemsgs')
                if leave_msgs is None:
                    self.__persondict.get(sayswho).update({'leavemsgs': [says]})
                    leave_msgs_num = 1
                else:
                    leave_msgs.append(says)
                    self.__persondict.get(sayswho).update({'leavemsgs': leave_msgs})
                    leave_msgs_num = len(leave_msgs)
                listitem = self.__persondict.get(sayswho).get('li')
                listitem.setText("%s %s %s" % (listitem.data(7),str(sayswho), listitem.data(6)) + ' got new messages(%d)' % leave_msgs_num)

    #提供给doclient调用，Q接收private says
    def recvprivatesays(self,sayswho,says):
        sayswho = int(sayswho)
        listitem = self.__frienddict.get(sayswho).get('li')
        if listitem is None:# 异常，忽略
            return
        Qprivate = self.__frienddict.get(sayswho).get('Q')
        if Qprivate is not None:#窗口是否已打开
            Qprivate.appendsays(says)
        else:#以下为留言功能
            leave_msgs = self.__frienddict.get(sayswho).get('leavemsgs')
            if leave_msgs is None:
                self.__frienddict.get(sayswho).update({'leavemsgs':[says]})
                leave_msgs_num = 1
            else:
                leave_msgs.append(says)
                self.__frienddict.get(sayswho).update({'leavemsgs': leave_msgs})
                leave_msgs_num =len(leave_msgs)
            listitem = self.__frienddict.get(sayswho).get('li')
            listitem.setText("%s %s"%(str(sayswho),listitem.data(6)) + ' got new messages(%d)' % leave_msgs_num)
        pass

    #提供给clientdo调用，Q接收groupsays
    def recvgroupsays(self,sayswho,saystogroup,says):
        if 0 == saystogroup:#广播public
            # timestr = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
            # timestr = time.strftime('%H:%M:%S', time.localtime(time.time()))
            #根据sayswho获取其name
            listitem = self.__frienddict.get(sayswho).get('li')
            if listitem is None:
                self._log("exception, friend %d,who's listitem is None"%sayswho)
                return
            name = listitem.data(6)
            timestr = ''
            self.ui.textBrowser.append('【%s %s'%(str(sayswho),name) +  timestr + ' says】:' + says)
            #self.ui.textBrowser.append('【' + str(sayswho) + timestr + ' says】:' + says)
            self.ui.textBrowser.moveCursor(QTextCursor.End)
        else:#组播处理
            pass

    def closeEvent(self, QCloseEvent):
        #关闭所有已打开的'Q'
        for ikey in self.__frienddict.keys():
            Qprivate = self.__frienddict.get(ikey).get('Q')
            if Qprivate is not None:
                Qprivate.close()

    def disconnect(self):#处理底层连接丢失
        self.ui.lbl_talkid.setText(self.ui.lbl_talkid.text()+" disconnect!!")
        s = self.ui.lbl_talkid.text()
        pass

    def reconnect(self):#处理底层链接回复
        self.ui.lbl_talkid.setText('welcome, %s %s'%(str(self.__saysme),self.__saysmename))
        pass

from login import Ui_fm_login
class Qlogin(QWidget):
    def __init__(self,okf):
        super(Qlogin,self).__init__()
        self.ui = Ui_fm_login()
        self.ui.setupUi(self)
        self.__okf = okf
        self.ui.pb_ok.clicked.connect(self.__okclicked)
        self.ui.pb_no.clicked.connect(self.__noclicked)
        self.ui.le_password.returnPressed.connect(self.__okclicked)

    def __okclicked(self):
        if self.__okf is not None:
            ikey = self.ui.le_id.text()
            password = self.ui.le_password.text()
            if ikey == '' or password =='':
                return
            self.ui.lb_reason.setText('登录中...')
            r = self.__okf(ikey,password)
            if r == -1:#数据发送失败,可能底层连接未完成
                self.ui.lb_reason.setText('数据发送失败,底层连接失败或未完成,请重试..')
                pass
            elif r == -2:#登录认证失败，用户名和密码错误或未注册
                self.ui.lb_reason.setText('登录认证失败，用户名和密码错误或未注册')
                pass
            elif r == -3:#不能重复登录
                self.ui.lb_reason.setText('不能重复登录')
            elif r == -4:
                self.ui.lb_reason.setText('未能登录，可能服务器异常')
            else:
                pass

    def __noclicked(self):
        self.close()

from psays_layout import Ui_Form
class Qpsays(QWidget):
    def __init__(self):
        super(Qpsays, self).__init__()
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.show()

if __name__ == '__main__':
    import  sys
    from PyQt5.QtWidgets import QApplication
    app = QApplication(sys.argv)
    print(sys.argv)
    co = Qonline()
